#include <stdlib.h>
#include "../card_crypto.h"
#include "card_nxp520.h"
#include "card_mifare.h"
#include "m1_card_key.h"

#define CARD_CRYPTO_M1_LOG(format, ...) OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)
#define __CARD_CRYPTO_M1_LOG(format, ...) __OSAL_LOG(C_CYAN format C_NONE, ##__VA_ARGS__)

static void idle_task_process(void)
{
}

/* 加密数据存储地址（卡片块地址） */
#define CARD_BLOCK_ADDR 64

/**
  * @brief  生成8字节真随机数
  * @note   
  *         
  * @param  pRandom：随机数缓存区（指向的存储空间必须要有8个字节）
  */
static void CardCrypto_GenerateRandomNumber(uint8_t *pRandom)
{
    Device_Crypto(CALC_RANDOM_NUMBER, NULL, 0, (uint32_t *)&pRandom[0], NULL);
    Device_Crypto(CALC_RANDOM_NUMBER, NULL, 0, (uint32_t *)&pRandom[4], NULL);
}

/**
  * @brief  获取3DES-KEY（对于M1加密卡，这个KEY当作随机数写入卡片内）
  * @note   如果KEY全为0，说明KEY未创建，使用硬件随机数创建KEY
  *         
  * @param  pKey：密钥缓存区（指向的存储空间必须要有16个字节）
  *
  * @return SUCCESS/ERROR
  */
static ErrorStatus CardCrypto_GetThreeDesKey(uint8_t *pKey)
{
    uint8_t temp[16], i;

    if (OSAL_NvRead(0, temp, sizeof(temp)) != SUCCESS)
    {
        return ERROR;
    }
    do
    {
        /* 判断3DES-KEY是否创建 */
        for (i = 0; i < sizeof(temp); i++)
        {
            if (temp[i] != 0)
            {
                memcpy(pKey, temp, sizeof(temp));
                return SUCCESS; //已创建
            }
        }

        /* 3DES-KEY未创建，生成真随机数，创建KEY */
        CardCrypto_GenerateRandomNumber(&temp[0]);
        CardCrypto_GenerateRandomNumber(&temp[8]);

        /* 随机数保存到EEPROM */
        if (OSAL_NvWrite(0, temp, sizeof(temp)) != SUCCESS)
        {
            return ERROR;
        }
    } while (1);
    return ERROR;
}

/**
  * @brief  获取卡片ID
  * @param  pCardId：卡片ID
  * @param  pType：卡片类型（CPU_CARD/M1_CARD）
  * @retval 卡片长度
  */
uint8_t CardCrypto_ReadCardId(uint8_t *pCardId, uint8_t *pType)
{
    uint16_t cardType, len;

    len = Nxp520_ReadCardId(pCardId, &cardType);
    if (cardType == 0x0400)
    {
        *pType = M1_CARD;
    }
    else
    {
        *pType = NO_CARD;
    }
    return len;
}

/**
  * @brief  写卡片中的某一个数据块（16byte）
  * @note   
  *         
  * @param  blockAddr：块地址
  * @param  pData：数据指针
  * @return 写入成功返回SUCCESS，写入失败或未知返回ERROR
  */
static ErrorStatus CardEncrypt_WriteDataBlock(uint8_t blockAddr, uint8_t *pData)
{
    uint8_t temp[16];

    if (Nxp520_write(blockAddr, pData) == MI_OK)
    {
        CARD_CRYPTO_M1_LOG("write ok\r\n");
        if (Nxp520_Read(blockAddr, temp) == MI_OK) //读取卡片内的数据块
        {
            CARD_CRYPTO_M1_LOG("read ok\r\n");
            if (memcmp(pData, temp, 16) == 0)
            {
                return SUCCESS;
            }
        }
    }
    return ERROR;
}

/**
  * @brief  验证卡片是否为合法卡片
  * @note   
  *         
  * @param  pCardId：卡片ID
  * @param  idLen：卡片ID长度
  *
  * @return SUCCESS/ERROR
  */
ErrorStatus CardCrypto_VerifyCard(uint8_t *pCardId, uint8_t idLen, uint8_t type, uint8_t *err)
{
    uint8_t keyA[6] = {0};
    uint8_t tempBuff[16] = {0};
    uint8_t readbuff[16] = {0};

    if (type != M1_CARD)
    {
        *err = CARD_ERR_TYPE;
        return ERROR;
    }

    idle_task_process();
    if (CardEncrypt_CardIdToKey(pCardId, idLen, keyA) == ERROR) //计算密码
    {
        return ERROR;
    }

    idle_task_process();
    if (Nxp520_Auth_State(0x60, CARD_BLOCK_ADDR, keyA, pCardId) == MI_OK) //验证Dxtc keyA
    {
        CARD_CRYPTO_M1_LOG("dxtc keyA verify succeed\r\n");

        idle_task_process();
        CardCrypto_GetThreeDesKey(tempBuff); //获取门锁随机数
        idle_task_process();
        if (Nxp520_Read(CARD_BLOCK_ADDR, readbuff) == MI_OK) //读取卡片内的随机值
        {
            CARD_CRYPTO_M1_LOG("Read card random number succeed\r\n");
            if (memcmp(tempBuff, readbuff, 16) == 0)
            {
                CARD_CRYPTO_M1_LOG("Verify card random number succeed\r\n");
                return SUCCESS;
            }
            CARD_CRYPTO_M1_LOG("Verify card random number failed\r\n");
        }
        else
        {
            CARD_CRYPTO_M1_LOG("Read card random number failed\r\n");
        }
        *err = CARD_ERR_NO_ADD;
    }
    else
    {
        *err = CARD_ERR_UNKNOW;
        CARD_CRYPTO_M1_LOG("dxtc keyA verify failed\r\n");
    }
    return ERROR;
}

/**
  * @brief  添加新卡片
  * @note   生成一个卡片密钥，写入CPU卡
  *         
  * @param  pCardId：卡片ID
  * @param  idLen：卡片ID长度
  *
  * @return SUCCESS/ERROR
  */
ErrorStatus CardCrypto_AddCard(uint8_t *pCardId, uint8_t idLen, uint8_t type)
{
    uint8_t keyA[6] = {0};
    uint8_t tempBuff[16] = {0};

    if (type != M1_CARD)
    {
        CARD_CRYPTO_M1_LOG("Card type error\r\n");
        return ERROR;
    }

    idle_task_process();
    if (CardEncrypt_CardIdToKey(pCardId, idLen, keyA) == ERROR) //计算密码
    {
        return ERROR;
    }

    idle_task_process();
    if (Nxp520_Auth_State(0x60, CARD_BLOCK_ADDR, keyA, pCardId) == MI_OK) //验证Dxtc keyA
    {
        CARD_CRYPTO_M1_LOG("dxtc keyA verify succeed\r\n");

        idle_task_process();
        CardCrypto_GetThreeDesKey(tempBuff); //获取门锁随机数
        idle_task_process();
        if (CardEncrypt_WriteDataBlock(CARD_BLOCK_ADDR, tempBuff) == SUCCESS)
        {
            CARD_CRYPTO_M1_LOG("Add card random number write succeed\r\n");
            return SUCCESS;
        }
        else
        {
            CARD_CRYPTO_M1_LOG("Add card random number write failed\r\n");
        }
    }
    else
    {
        CARD_CRYPTO_M1_LOG("dxtc keyA verify failed\r\n");
    }
    return ERROR;
}
